import { isArry, isObject } from "../utils";;
import { arrryMethods } from "./array";

//每个对象都有一个__proto__ 它指向所属类的原型 fn.__proto__=Function.prototype
//每个原型上都有一个constructor属性 指向函数本身 Function.prototype.constructor = Function

class Observer{
    constructor(value){
        value.__ob__ = this;
        if(isArry(value)){
            //更改数组原型方法(有兼容性问题可以采用循环的方式)
            value.__prop__ = arrryMethods;
        }else{
            this.walk(value);//核心就是循环对象
        }
    }
    walk(data){//循环对象且不要原型上的方法
        Object.keys(data).forEach(key=>{//要使用definedProperty重新定义
            defineReactive(data,key,data[key])
        })
    }
}

//1 性能优化的原则
//1) 不要把所有的数据都放在data中 因为所有的数据都会增加get set
//2) 不要写数据的时候 层次过深 尽量扁平化数据
// 3) 不要频繁获取数据
// 4) 如果数据不需要使用相应式 可以使用object.freeze冻结属性


//vue2 应用了defineProperty需要一加载的时候 就进行递归操作 所以好性能 如果层次过深也会浪费性能
function defineReactive(obj,key,value) {//vue2 慢的原因 主要在这个方法中
    observe(value);//递归进行观测数据 不管多少层 都进行defineProperty
    Object.defineProperties(obj,key,{
        get(){
            return value;//闭包 此value会像上层的value进行查找
        },
        set(newValue){
            if(newValue===value) return
            value = newValue;
        }
    })
}

export function observe(value) {
    // 1.如果value不是对象，就不用观测了 说明写的有问题
    if(!isObject(value)){
        return;
    }
    //需要对对象进行观测(最外层必须是一个{} 不能是数组)
    //如果一个数据已经被观测过了，就不要再观测了，用类来实现，我观测过了就增加一个标识，说明观测过了，在观测的时候，可以先检测是否观测过 如果观测过了就跳过检测
    return new Observer(value)
}